//
// Created by mio on 25-5-19.
//

#include <QGuiApplication>
#include <QDebug>


#include "SigConnection.h"
#include "../UI/tool/define.h"

int streamIndex = 1;

SigConnection::SigConnection(TaskScheduler *scheduler, int sockfd, const QString &code, const UserType &type)
    : TcpConnection(scheduler, sockfd)
    , state_(NONE)
    , type_(type)
    , code_(code)
{
    SetReadCallback([this](std::shared_ptr<TcpConnection> conn, BufferReader& buffer) {
        return this->OnRead(buffer);
    });

    SetCloseCallback([this](std::shared_ptr<TcpConnection> conn) {
        return this->OnClose();
    });

    screen_ = QGuiApplication::primaryScreen();
    Join();
}

SigConnection::~SigConnection()
{

}

bool SigConnection::OnRead(BufferReader &buffer)
{
    while (buffer.ReadableBytes() > 0)
    {
        HandleMessage(buffer);
    }
    return true;
}

void SigConnection::OnClose()
{
    quit_ = true;
}

// TODO: 做一个流程图搞清楚这块儿的业务逻辑
void SigConnection::HandleMessage(BufferReader &buffer)
{
    packet_head* head = (packet_head*)buffer.Peek();
    if (buffer.ReadableBytes() < head->len) { return; }
    // qDebug() << "CMD: " << head->cmd;
    switch (head->cmd) {
    case JOIN:
        qDebug() << "JOIN";
        doJoin(head);
        break;
    case PLAYSTREAM:
        qDebug() << "PLAYSTREAM";
        doPlayStream(head);
        break;
    case CREATESTREAM:
        qDebug() << "CREATESTREAM";
        doCtreatStream(head);
        break;
    case DELETESTREAM:
        qDebug() << "DELETESTREAM";
        doDeleteStream(head);
        break;
    case MOUSE:
        qDebug() << "MOUSE";
        doMouseEvent(head);
        break;
    case MOUSEMOVE:
        // qDebug() << "MOUSEMOVE";
        doMouseMoveEvent(head);
        break;
    case KEY:
        qDebug() << "KEY";
        doKeyEvent(head);
        break;
    case WHEEL:
        // qDebug() << "WHEEL";
        doWheelEvent(head);
        break;
    default:
        break;
    }
    buffer.Retrieve(head->len);
}

qint32 SigConnection::Join()
{
    // 当前已经创建房间
    if (state_ != NONE) { return -1; }
    Join_body body;
    if (type_ == CONTROLLED) { body.SetId(code_.toStdString()); } //设置识别码，由外部传入
    else { body.SetId("154564"); } // 设置识别码, 由外界传入
    this->Send((const char*)&body, body.len);
    return 0;
}

qint32 SigConnection::obtainStream()
{
    if (state_ == IDLE && type_ == CONTROLLED) {
        ObtainStream_body body;
        body.SetId(code_.toStdString());
        this->Send((const char*)&body, body.len); // id就是标识符，每个客户端有一个标识符
        return 0;
    }
    return -1;
}

void SigConnection::doJoin(const packet_head *data)
{
    //处理创建房间
    JoinReply_body* reply = (JoinReply_body*)data;
    if (reply->result == S_OK) {
        state_ = IDLE;
        if (type_ == CONTROLLED)
        {
            if (obtainStream() != 0) qDebug() << "获取流请求发送失败";
            else
            {
                state_ = PULLER;
                qDebug() << "获取流请求发送成功";
            }
        }
    }
    //如果是控制端 ，创建成功之后，我们需要申请获取流
    //如果是被控端，就不需要处理
}

void SigConnection::doPlayStream(const packet_head *data)
{
    if (state_ == PULLER && type_ == CONTROLLED) {
        PlayStream_body* playStream = (PlayStream_body*)data;
        if (playStream->result == S_OK)
        {
            qDebug() << "开始播放流";
            if (startStreamCb_) { startStreamCb_(QString::fromStdString(playStream->GetStreamAddres())); }
        }
        else { qDebug() << "播放流失败"; }
    }
}

void SigConnection::doCtreatStream(const packet_head *data)
{
    if (state_ == IDLE && type_ == CONTROLLED)
    {
        CreateStreamReply_body reply;
        QString streamAddr = "rtmp://192.168.31.38:1925/live/" + QString::number(++streamIndex);
        // 开始推流
        if (startStreamCb_(streamAddr))
        {
            reply.SetStreamAddres(streamAddr.toStdString());
            reply.SetCode((ResultCode)0);
            qDebug() << "streamaddr: " << reply.GetStreamAddres().c_str() << "len: " << reply.len;
            this->Send((const char*)&reply, reply.len);
            state_ == PUSHER;
        }
        else
        {
            qDebug() << "streamaddr failed";
            reply.SetCode(SERVER_ERROR);
            this->Send((const char*)&reply, reply.len);
        }
    }
}

void SigConnection::doDeleteStream(const packet_head *data)
{
    //删除流 如果推流端发现这个拉流数量为0,我们就需要停止推流，如果有一个或者多个拉流端就需要继续推流‘
    DeleteStream_body* body = (DeleteStream_body*)data;
    if (body->streamCount == 0)
    {
        if (stopStreamCb_) { stopStreamCb_(); }
    }
}

void SigConnection::doMouseEvent(const packet_head *data)
{
    Mouse_Body* body = (Mouse_Body*)data;
    DWORD dwFlags = 0;
    if (body->type == PRESS)
    {
        dwFlags |= (body->mouseButtons & MouseType::LeftButton) ? MOUSEEVENTF_LEFTDOWN : 0;
        dwFlags |= (body->mouseButtons & MouseType::RightButton) ? MOUSEEVENTF_RIGHTDOWN : 0;
        dwFlags |= (body->mouseButtons & MouseType::MiddleButton) ? MOUSEEVENTF_MIDDLEDOWN : 0;
    }
    else if (body->type == RELEASE)
    {
        dwFlags |= (body->mouseButtons & MouseType::LeftButton) ? MOUSEEVENTF_LEFTUP: 0;
        dwFlags |= (body->mouseButtons & MouseType::RightButton) ? MOUSEEVENTF_RIGHTUP : 0;
        dwFlags |= (body->mouseButtons & MouseType::MiddleButton) ? MOUSEEVENTF_MIDDLEUP : 0;
    }
    // 模拟事件
    if (dwFlags != 0) {
        INPUT input = { 0 };
        input.type = INPUT_MOUSE;
        input.mi.dwFlags = dwFlags;
        SendInput(1, &input, sizeof(INPUT));
    }
}

void SigConnection::doMouseMoveEvent(const packet_head *data)
{
    //鼠标移动
    //传来的时候他是一个double 左边和右边，我们需要去组成浮点数，这个值他是一个比值(x/w,y/h),组成一个浮点数，
    //乘上当前这个电脑高/宽，来获取当前的坐标

    MouseMove_Body* body = (MouseMove_Body*)data;
    //获取当前电脑宽高
    // qDebug() << "Screen : width: " << screen_->size().width() << "height: " << screen_->size().height();

    // 1. 重新组合百分比
    double combined_x_percent = (static_cast<double>(body->xl_ratio) + (static_cast<double>(body->xr_ratio) / 100.0f)); // 得到 xx.yy 形式的百分比
    double combined_y_percent = (static_cast<double>(body->yl_ratio) + (static_cast<double>(body->yr_ratio) / 100.0f)); // 得到 yy.xx 形式的百分比

    // 将百分比转换为 0.0 - 1.0 范围的比例值
    double ratio_x = combined_x_percent / 100.0f;
    double ratio_y = combined_y_percent / 100.0f;

    // 2. 计算屏幕绝对坐标
    // screen_->size() 通常返回逻辑像素 (device-independent pixels)
    // QCursor::setPos() 也通常使用逻辑像素
    // 因此，除以 devicePixelRatio 可能是不必要的，甚至可能是错误的，除非 screen_->size() 返回的是物理像素。
    // 假设 screen_->size() 返回逻辑像素:
    int x = static_cast<int>(ratio_x * screen_->size().width());
    int y = static_cast<int>(ratio_y * screen_->size().height());

    // 原代码中的 devicePixelRatio 使用:
    // int x = static_cast<int>(ratio_x * screen_->size().width() / screen_->devicePixelRatio());
    // int y = static_cast<int>(ratio_y * screen_->size().height() / screen_->devicePixelRatio());

    // qDebug() << "x: " << x << "y: " << y;
    QCursor::setPos(x,y);
}

void SigConnection::doKeyEvent(const packet_head *data)
{
    //获取键值去模拟
    Key_Body* body = (Key_Body*)data;
    DWORD vk = body->key;
    qDebug() << "key: " << vk;
    INPUT input[1];
    ZeroMemory(input, sizeof(input));
    //操作类型是按下，松开
    int op = body->type ? KEYEVENTF_KEYUP : 0;
    input[0].type = INPUT_KEYBOARD;
    input[0].ki.wVk = vk;
    input[0].ki.dwFlags = op;
    input[0].ki.wScan = MapVirtualKey(vk, 0);
    input[0].ki.time = 0;
    input[0].ki.dwExtraInfo = 0;
    SendInput(1, input, sizeof(input));
}

void SigConnection::doWheelEvent(const packet_head *data)
{
    Wheel_Body* body = (Wheel_Body*)data;
    INPUT input = { 0 };
    input.type = INPUT_MOUSE;
    input.mi.dwFlags = MOUSEEVENTF_WHEEL;
    input.mi.mouseData = body->wheel * 240;
    SendInput(1, &input, sizeof(input));
}
